﻿Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Workflow.ComponentModel.Design

Namespace System.Workflow.ComponentModel
    Friend NotInheritable Class Walker
        ' Events
        Friend Custom Event FoundActivity As WalkerEventHandler
        Friend Custom Event FoundProperty As WalkerEventHandler

        ' Methods
        Public Sub New()
            Me.New(False)
        End Sub

        Public Sub New(ByVal useEnabledActivities As Boolean)
            Me.useEnabledActivities = useEnabledActivities
        End Sub

        Private Shared Function GetSerializationVisibility(ByVal prop As PropertyInfo) As DesignerSerializationVisibility
            If ((prop.DeclaringType Is GetType(CompositeActivity)) AndAlso String.Equals(prop.Name, "Activities", StringComparison.Ordinal)) Then
                Return DesignerSerializationVisibility.Hidden
            End If
            Dim visible As DesignerSerializationVisibility = DesignerSerializationVisibility.Visible
            Dim customAttributes As DesignerSerializationVisibilityAttribute() = DirectCast(prop.GetCustomAttributes(GetType(DesignerSerializationVisibilityAttribute), True), DesignerSerializationVisibilityAttribute())
            If (customAttributes.Length > 0) Then
                visible = customAttributes(0).Visibility
            End If
            Return visible
        End Function

        Private Shared Function IsBrowsableType(ByVal type As Type) As Boolean
            Dim browsable As Boolean = False
            Dim customAttributes As BrowsableAttribute() = DirectCast(type.GetCustomAttributes(GetType(BrowsableAttribute), True), BrowsableAttribute())
            If (customAttributes.Length > 0) Then
                browsable = customAttributes(0).Browsable
            End If
            Return browsable
        End Function

        Public Sub Walk(ByVal seedActivity As Activity)
            Me.Walk(seedActivity, True)
        End Sub

        Public Sub Walk(ByVal seedActivity As Activity, ByVal walkChildren As Boolean)
            Dim queue As New Queue
            queue.Enqueue(seedActivity)
            Do While (queue.Count > 0)
                Dim currentActivity As Activity = [TryCast](queue.Dequeue,Activity)
                If (Not Me.FoundActivity Is Nothing) Then
                    Dim eventArgs As New WalkerEventArgs(currentActivity)
                    Me.FoundActivity.Invoke(Me, eventArgs)
                    If (eventArgs.Action = WalkerAction.Abort) Then
                        Return
                    End If
                    If (eventArgs.Action = WalkerAction.Skip) Then
                        [Continue] Do
                    End If
                End If
                If ((Not Me.FoundProperty Is Nothing) AndAlso Not Me.WalkProperties(currentActivity)) Then
                    Return
                End If
                If (walkChildren AndAlso TypeOf currentActivity Is CompositeActivity) Then
                    If Me.useEnabledActivities Then
                        Dim activity2 As Activity
                        For Each activity2 In Helpers.GetAllEnabledActivities(DirectCast(currentActivity, CompositeActivity))
                            queue.Enqueue(activity2)
                        Next
                    Else
                        Dim activity3 As Activity
                        For Each activity3 In DirectCast(currentActivity, CompositeActivity).Activities
                            queue.Enqueue(activity3)
                        Next
                    End If
                End If
            Loop
        End Sub

        Private Function WalkProperties(ByVal seedActivity As Activity) As Boolean
            Return Me.WalkProperties(seedActivity, seedActivity)
        End Function

        Public Function WalkProperties(ByVal activity As Activity, ByVal obj As Object) As Boolean
            Dim activity2 As Activity = [TryCast](obj,Activity)
            Dim info As PropertyInfo
            For Each info In obj.GetType.GetProperties((BindingFlags.Public Or BindingFlags.Instance))
                If (((info.GetIndexParameters Is Nothing) OrElse (info.GetIndexParameters.Length <= 0)) AndAlso (Walker.GetSerializationVisibility(info) <> DesignerSerializationVisibility.Hidden)) Then
                    Dim currentValue As Object = Nothing
                    Dim dependencyProperty As DependencyProperty = DependencyProperty.FromName(info.Name, obj.GetType)
                    If ((Not dependencyProperty Is Nothing) AndAlso (Not activity2 Is Nothing)) Then
                        If activity2.IsBindingSet(dependencyProperty) Then
                            currentValue = activity2.GetBinding(dependencyProperty)
                        Else
                            currentValue = activity2.GetValue(dependencyProperty)
                        End If
                    Else
                        Try 
                            currentValue = If(info.CanRead, info.GetValue(obj, Nothing), Nothing)
                        Catch obj1 As Object
                        End Try
                    End If
                    If (Not Me.FoundProperty Is Nothing) Then
                        Dim eventArgs As New WalkerEventArgs(activity, currentValue, info, obj)
                        Me.FoundProperty.Invoke(Me, eventArgs)
                        If (eventArgs.Action = WalkerAction.Skip) Then
                            goto Label_01A8
                        End If
                        If (eventArgs.Action = WalkerAction.Abort) Then
                            Return False
                        End If
                    End If
                    If TypeOf currentValue Is IList Then
                        Dim obj3 As Object
                        For Each obj3 In DirectCast(currentValue, IList)
                            If (Not Me.FoundProperty Is Nothing) Then
                                Dim args2 As New WalkerEventArgs(activity, obj3, Nothing, currentValue)
                                Me.FoundProperty.Invoke(Me, args2)
                                If (args2.Action = WalkerAction.Skip) Then
                                    [Continue] For
                                End If
                                If (args2.Action = WalkerAction.Abort) Then
                                    Return False
                                End If
                            End If
                            If (((Not obj3 Is Nothing) AndAlso Walker.IsBrowsableType(obj3.GetType)) AndAlso Not Me.WalkProperties(activity, obj3)) Then
                                Return False
                            End If
                        Next
                    ElseIf (((Not currentValue Is Nothing) AndAlso Walker.IsBrowsableType(currentValue.GetType)) AndAlso Not Me.WalkProperties(activity, currentValue)) Then
                        Return False
                    End If
                Label_01A8:
                End If
            Next
            Return True
        End Function


        ' Fields
        Private useEnabledActivities As Boolean
    End Class
End Namespace

